package com.quectel.cms.controller.village;

import com.quectel.cms.controller.BaseController;
import com.quectel.cms.util.SessionHolder;
import com.quectel.constant.global.SystemConstants;
import com.quectel.util.aspect.log.annotation.Log;
import com.quectel.constant.global.annotation.RequirePermissions;
import com.quectel.core.module.village.dto.VillageBuildingDto;
import com.quectel.core.module.village.dto.VillageDto;
import com.quectel.core.module.village.dto.VillageFloorDto;
import com.quectel.core.module.village.dto.VillageRoomDto;
import com.quectel.core.module.village.service.VillageBuildingService;
import com.quectel.core.module.village.service.VillageFloorService;
import com.quectel.core.module.village.service.VillageService;
import com.quectel.util.common.POIUtils;
import com.quectel.util.common.Page;
import com.quectel.util.common.Request;
import com.quectel.util.common.Response;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * @author caolu
 * @email louis.cao@quectel.com
 * @date 2021-10-18 14:40:54
 */
@RestController
@RequestMapping("villageBuilding")
@Tag(name = "VillageBuildingController", description = "小区楼栋相关api")
public class VillageBuildingController extends BaseController {
    @DubboReference
    private VillageService villageService;
    @DubboReference
    private VillageBuildingService villageBuildingService;
    @DubboReference
    private VillageFloorService villageFloorService;


    /**
     * 列表
     */
    @PostMapping("importExcel")
    @RequirePermissions(values = "villageBuilding:importExcel")
    @Operation(summary = "excel导入楼栋信息")
    @Log(express = "导入楼栋信息")
    public Response<Object> importExcel(
            MultipartHttpServletRequest request
    ) {
        int totalCount = 0;
        int successCount = 0;
        List<VillageBuildingDto> villageBuildingDtos = new ArrayList<>();
        Iterator<String> fileNames = request.getFileNames();
        while (fileNames.hasNext()) {
            String next = fileNames.next();
            List<MultipartFile> files = request.getFiles(next);
            for (MultipartFile file : files) {
                try {
                    //校验楼栋数据合法性
                    List<Map<Integer, String>> analysis = POIUtils.analysis(file.getInputStream(), 1, 0);
                    for (Map<Integer, String> map : analysis) {
                        ++totalCount;
                        try {
                            VillageDto villageDto = villageService.selectByName(SessionHolder.getSysUser().getTenantId(), map.get(0));
                            if (villageDto == null) {
                                continue;
                            }
                            VillageBuildingDto villageBuildingDto = new VillageBuildingDto();
                            villageBuildingDto.setVillageId(villageDto.getId());
                            villageBuildingDto.setName(map.get(1));
                            villageBuildingDto.setUndergroundFloors(Integer.valueOf(map.get(2)));
                            villageBuildingDto.setGroundFloors(Integer.valueOf(map.get(3)));
                            villageBuildingDto.setLongitude(StringUtils.isNotBlank(map.get(4)) ? Double.valueOf(map.get(4)) : null);
                            villageBuildingDto.setLatitude(StringUtils.isNotBlank(map.get(5)) ? Double.valueOf(map.get(5)) : null);
                            villageBuildingDto.setAutoGenFloorAndRoom("是".equals(map.get(6)) ? SystemConstants.YES : SystemConstants.NO);
                            villageBuildingDto.setRoomNum(SystemConstants.YES.equals(villageBuildingDto.getAutoGenFloorAndRoom()) ? Integer.valueOf(map.get(7)) : 0);
                            fillSaveCommonData(villageBuildingDto);
                            villageBuildingDtos.add(villageBuildingDto);
                        } catch (Exception e) {
                            logger.error("表格中有错误数据", e);
                        }
                    }
                } catch (Exception e) {
                    logger.error("解析楼栋信息出错", e);
                }
            }
        }
        for (VillageBuildingDto villageBuildingDto : villageBuildingDtos) {
            try {
                VillageBuildingDto dbValue = villageBuildingService.selectByName(villageBuildingDto.getVillageId(), villageBuildingDto.getName());
                if (dbValue != null) {
                } else {
                    Long id = villageBuildingService.save(villageBuildingDto);
                    villageBuildingDto.setId(id);
                }

                if (SystemConstants.YES.equals(villageBuildingDto.getAutoGenFloorAndRoom())) {
                    List<VillageFloorDto> floors = villageFloorService.selectByBuildingId(villageBuildingDto.getId());
                    if (floors.size() > 0) {
                        continue;
                    }
                    autoGenerateFloorAndRoom(Arrays.asList(villageBuildingDto));
                }
                ++successCount;
            } catch (Exception e) {
                logger.error("保存导入数据出错", e);
            }

        }
        return Response.error("导入数据完成，总条数:" + totalCount + "成功条数:" + successCount);
    }

    /**
     * 列表
     */
    @GetMapping("exportExcel")
    @RequirePermissions(values = "villageBuilding:exportExcel")
    @Log(express = "导出小区信息")
    @Operation(summary = "导出楼栋信息为excel文件")
    public void exportExcel(@RequestParam Map<String, Object> params, HttpServletResponse hresp) {
        Request request = Request.configParamsNotPage(params);

        super.fillAuthorityData(params);

        List<VillageBuildingDto> result = new ArrayList<>();
        int pageNo = 0;
        params.put("limit", 1000);
        while (true) {
            params.put("offset", pageNo++ * 1000);
            List<VillageBuildingDto> list = villageBuildingService.queryList(params);
            if (org.apache.commons.collections4.CollectionUtils.isEmpty(list)) {
                break;
            }
            result.addAll(list);
            if (list.size() < 1000) {
                break;
            }
        }
        String[] headers = new String[]{"所属小区", "楼栋名称", "地下层数", "地上层数", "经度", "纬度"};
        List<String[]> dataList = new ArrayList<>();
        for (VillageBuildingDto data : result) {
            String[] item = new String[headers.length];
            item[0] = data.getVillageName();
            item[1] = data.getName();
            item[2] = data.getUndergroundFloors() + "";
            item[3] = data.getGroundFloors() + "";
            item[4] = data.getLongitude() != null ? data.getLongitude() + "" : "";
            item[5] = data.getLatitude() != null ? data.getLatitude() + "" : "";
            dataList.add(item);
        }
        POIUtils.exportExcel(hresp, "楼栋信息", headers, dataList, "楼栋信息");

    }

    /**
     * 列表
     */
    @GetMapping("queryByVillageId")
    @Operation(summary = "根据小区id筛选楼栋信息")
    public Response<List<VillageBuildingDto>> queryByVillageId(
            @Parameter(description = "小区") @RequestParam Long villageId
    ) {

        return Response.<List<VillageBuildingDto>>ok().wrap(villageBuildingService.selectByVillageId(villageId));
    }

    /**
     * 根据参数分页查询楼栋信息列表
     */
    @GetMapping("list")
    @RequirePermissions(values = "villageBuilding:list")
    @Operation(summary = "根据参数分页查询楼栋信息列表")
    public Response<Page<VillageBuildingDto>> list(
            @Parameter(description = "从1开始的页码数") @RequestParam Integer pageNo,
            @Parameter(description = "每页多少条") @RequestParam Integer pageSize
    ) {
        //查询列表数据
        Request request = Request.configParams(Request.parseParams(httpServletRequest));

        super.fillAuthorityData(request.getParams());
        int total = villageBuildingService.queryTotal(request.getParams());

        List<VillageBuildingDto> list = null;
        if (total > 0) {
            list = villageBuildingService.queryList(request.getParams());
        } else {
            list = new ArrayList<>();
        }

        Page<VillageBuildingDto> page = new Page<>(request.getPageNo(), request.getPageSize(), total, list);
        return Response.<Page<VillageBuildingDto>>ok().wrap(page);
    }


    /**
     * 查询小区楼栋信息列表
     */
    @GetMapping("info/{id}")
    @RequirePermissions(values = "villageBuilding:info")
    @Operation(summary = "查询小区楼栋信息列表")
    public Response<VillageBuildingDto> info(@PathVariable("id") Long id) {
        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);
        params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(id));
        if (villageBuildingService.queryTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }

        VillageBuildingDto villageBuildingDto = villageBuildingService.selectById(id);

        return Response.<VillageBuildingDto>ok().wrap(villageBuildingDto);
    }

    /**
     * 保存小区楼栋信息列表
     */
    @PostMapping("save")
    @RequirePermissions(values = "villageBuilding:edit")
    @Operation(summary = "保存小区楼栋信息列表")
    @Log(express = "新增楼栋")
    public Response<Object> save(@RequestBody @Validated VillageBuildingDto villageBuildingDto) {

        VillageBuildingDto dbValue = villageBuildingService.selectByName(villageBuildingDto.getVillageId(), villageBuildingDto.getName());
        if (dbValue != null) {
            return Response.error("该楼栋已经存在");
        }
        //填充基础数据
        fillSaveCommonData(villageBuildingDto);

        Long id = villageBuildingService.save(villageBuildingDto);
        villageBuildingDto.setId(id);

        if (SystemConstants.YES.equals(villageBuildingDto.getAutoGenFloorAndRoom())) {
            autoGenerateFloorAndRoom(Arrays.asList(villageBuildingDto));
        }


        return Response.ok();
    }

    /**
     * 修改小区楼栋信息
     */
    @PostMapping("update")
    @RequirePermissions(values = "villageBuilding:edit")
    @Operation(summary = "修改小区楼栋信息")
    @Log(express = "编辑楼栋")
    public Response<Object> update(@RequestBody @Validated VillageBuildingDto villageBuildingDto) {

        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);
        params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(villageBuildingDto.getId()));
        if (villageBuildingService.queryTotal(params) <= 0) {
            return Response.error(SystemConstants.ILLEGAL_MSG);
        }
        VillageBuildingDto dbValue = villageBuildingService.selectByName(villageBuildingDto.getVillageId(), villageBuildingDto.getName());
        if (dbValue != null && !Objects.equals(dbValue.getId(), villageBuildingDto.getId())) {
            return Response.error("该楼栋已经存在");
        }

        if (SystemConstants.YES.equals(villageBuildingDto.getAutoGenFloorAndRoom())) {
            List<VillageFloorDto> floors = villageFloorService.selectByBuildingId(villageBuildingDto.getId());
            if (floors.size() > 0) {
                return Response.error("该楼栋下已存在楼层信息,不允许自动生成");
            }
            autoGenerateFloorAndRoom(Arrays.asList(villageBuildingDto));
        }


        //填充基础数据
        fillEditCommonData(villageBuildingDto);

        villageBuildingService.updateById(villageBuildingDto);


        return Response.ok();
    }

    /**
     * 同时生成多栋楼的信息
     *
     * @param buildings
     */
    private void autoGenerateFloorAndRoom(List<VillageBuildingDto> buildings) {
        List<VillageFloorDto> floors = new ArrayList<>();

        for (VillageBuildingDto building : buildings) {

            //生成楼层和房间
            for (int i = building.getUndergroundFloors() * -1; i <= building.getGroundFloors(); i++) {
                if (i == 0) {
                    //没有第0层
                    continue;
                }
                VillageFloorDto villageFloorDto = new VillageFloorDto();
                villageFloorDto.setVillageId(building.getVillageId());
                villageFloorDto.setBuildingId(building.getId());
                villageFloorDto.setFloorNo(i);
                if (i < 0) {
                    villageFloorDto.setName("地下" + i + "层");
                } else {
                    villageFloorDto.setName("第" + i + "层");
                }
                fillSaveCommonData(villageFloorDto);

                if (i > 0) {
                    List<VillageRoomDto> roomList = new ArrayList<>();
                    //生成地上的房屋
                    for (int j = 1; j <= building.getRoomNum(); j++) {
                        VillageRoomDto villageRoomDto = new VillageRoomDto();
                        villageRoomDto.setVillageId(building.getVillageId());
                        villageRoomDto.setBuildingId(building.getId());
                        villageRoomDto.setName(i + String.format("%02d", j) + "室");
                        fillSaveCommonData(villageRoomDto);
                        roomList.add(villageRoomDto);
                    }
                    villageFloorDto.setVillageRoomDtoList(roomList);
                }
                floors.add(villageFloorDto);
            }
        }
        villageFloorService.generateByBuildingsConfig(floors);

    }

    /**
     * 批量删除小区楼栋信息记录
     */
    @PostMapping("delete")
    @RequirePermissions(values = "villageBuilding:delete")
    @Operation(summary = "批量删除小区楼栋信息记录")
    @Log(express = "删除楼栋")
    public Response<Object> delete(@RequestBody Long[] ids) {


        Map<String, Object> params = new HashMap<>();
        super.fillAuthorityData(params);

        for (Long id : ids) {

            params.remove(SystemConstants.ENTITY_ID_FLAG);
            params.put(SystemConstants.ENTITY_ID_FLAG, String.valueOf(id));

            if (villageBuildingService.queryTotal(params) <= 0) {
                return Response.error(SystemConstants.ILLEGAL_MSG);
            }
            List<VillageFloorDto> floors = villageFloorService.selectByBuildingId(id);
            if (floors.size() > 0) {
                return Response.error("该楼栋下已存在楼层信息,不允许删除");
            }
        }


        villageBuildingService.deleteBatch(ids);

        return Response.ok();
    }
}
